package com.example.nginx;

import java.io.*;
import java.nio.file.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import java.util.logging.Level;

/**
 * 日志轮转管理器
 * 支持按文件大小和时间进行日志轮转
 */
public class LogRotationManager {
    private static final Logger logger = Logger.getLogger(LogRotationManager.class.getName());
    
    private final String baseLogFile;
    private final long maxFileSize;
    private final TimeRotationInterval timeInterval;
    private final int maxFiles;
    private final String filePattern;
    private final String rotationDirectory;
    private final boolean enabled;
    
    private long currentFileSize = 0;
    private File currentLogFile;
    private PrintWriter currentWriter;
    private final SimpleDateFormat dateFormat;
    private final ScheduledExecutorService scheduler;
    private Date lastRotationTime;
    
    public enum TimeRotationInterval {
        NONE, HOUR, DAY, WEEK
    }
    
    public LogRotationManager(String baseLogFile, boolean enabled, long maxFileSize, 
                             TimeRotationInterval timeInterval, int maxFiles, 
                             String filePattern, String rotationDirectory) {
        this.baseLogFile = baseLogFile;
        this.enabled = enabled;
        this.maxFileSize = maxFileSize;
        this.timeInterval = timeInterval;
        this.maxFiles = maxFiles;
        this.filePattern = filePattern;
        this.rotationDirectory = rotationDirectory;
        this.dateFormat = new SimpleDateFormat(filePattern);
        this.scheduler = Executors.newScheduledThreadPool(1);
        this.lastRotationTime = new Date();
        
        initialize();
    }
    
    /**
     * 初始化日志管理器
     */
    private void initialize() {
        if (!enabled) {
            logger.info("日志轮转功能已禁用");
            return;
        }
        
        try {
            // 创建轮转目录
            if (rotationDirectory != null && !rotationDirectory.isEmpty()) {
                Path rotationPath = Paths.get(rotationDirectory);
                if (!Files.exists(rotationPath)) {
                    Files.createDirectories(rotationPath);
                    logger.info("创建轮转目录: " + rotationDirectory);
                }
            }
            
            // 初始化当前日志文件
            currentLogFile = new File(baseLogFile);
            if (currentLogFile.exists()) {
                currentFileSize = currentLogFile.length();
            }
            
            // 创建文件写入器
            currentWriter = new PrintWriter(new BufferedWriter(new FileWriter(currentLogFile, true)));
            
            // 设置定时轮转
            if (timeInterval != TimeRotationInterval.NONE) {
                scheduleTimeRotation();
            }
            
            logger.info("日志轮转管理器初始化完成");
            logger.info(String.format("配置: 最大文件大小=%d字节, 时间间隔=%s, 最大文件数=%d", 
                    maxFileSize, timeInterval, maxFiles));
            
        } catch (IOException e) {
            logger.severe("初始化日志轮转管理器失败: " + e.getMessage());
            throw new RuntimeException("无法初始化日志轮转管理器", e);
        }
    }
    
    /**
     * 写入日志行
     */
    public synchronized void writeLog(String logLine) {
        if (!enabled) {
            // 如果轮转未启用，直接写入原文件
            try (FileWriter writer = new FileWriter(baseLogFile, true);
                 BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
                bufferedWriter.write(logLine);
                bufferedWriter.newLine();
            } catch (IOException e) {
                logger.severe("写入日志失败: " + e.getMessage());
            }
            return;
        }
        
        try {
            // 检查是否需要按大小轮转
            if (maxFileSize > 0 && currentFileSize >= maxFileSize) {
                rotateBySize();
            }
            
            // 写入日志
            currentWriter.println(logLine);
            currentWriter.flush();
            currentFileSize += logLine.getBytes().length + System.lineSeparator().getBytes().length;
            
        } catch (Exception e) {
            logger.severe("写入日志时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 按大小轮转日志
     */
    private void rotateBySize() {
        try {
            logger.info("按大小轮转日志文件，当前大小: " + currentFileSize + " 字节");
            
            // 关闭当前写入器
            currentWriter.close();
            
            // 生成轮转文件名
            String rotationFileName = generateRotationFileName("size");
            File rotationFile = new File(rotationDirectory, rotationFileName);
            
            // 移动当前文件到轮转文件
            Files.move(currentLogFile.toPath(), rotationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            
            // 创建新的日志文件
            currentLogFile = new File(baseLogFile);
            currentWriter = new PrintWriter(new BufferedWriter(new FileWriter(currentLogFile, true)));
            currentFileSize = 0;
            
            // 清理旧文件
            cleanupOldFiles();
            
            logger.info("日志轮转完成: " + rotationFile.getName());
            
        } catch (IOException e) {
            logger.severe("按大小轮转日志失败: " + e.getMessage());
        }
    }
    
    /**
     * 按时间轮转日志
     */
    private void rotateByTime() {
        try {
            logger.info("按时间轮转日志文件");
            
            // 关闭当前写入器
            currentWriter.close();
            
            // 生成轮转文件名
            String rotationFileName = generateRotationFileName("time");
            File rotationFile = new File(rotationDirectory, rotationFileName);
            
            // 如果当前日志文件存在内容，则进行轮转
            if (currentLogFile.exists() && currentLogFile.length() > 0) {
                Files.move(currentLogFile.toPath(), rotationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            }
            
            // 创建新的日志文件
            currentLogFile = new File(baseLogFile);
            currentWriter = new PrintWriter(new BufferedWriter(new FileWriter(currentLogFile, true)));
            currentFileSize = 0;
            lastRotationTime = new Date();
            
            // 清理旧文件
            cleanupOldFiles();
            
            logger.info("时间轮转完成: " + rotationFile.getName());
            
        } catch (IOException e) {
            logger.severe("按时间轮转日志失败: " + e.getMessage());
        }
    }
    
    /**
     * 生成轮转文件名
     */
    private String generateRotationFileName(String rotationType) {
        String timestamp = dateFormat.format(new Date());
        String baseName = new File(baseLogFile).getName();
        String nameWithoutExt = baseName.contains(".") ? 
            baseName.substring(0, baseName.lastIndexOf('.')) : baseName;
        String ext = baseName.contains(".") ? 
            baseName.substring(baseName.lastIndexOf('.')) : "";
        
        return String.format("%s_%s_%s%s", nameWithoutExt, rotationType, timestamp, ext);
    }
    
    /**
     * 设置定时轮转
     */
    private void scheduleTimeRotation() {
        long delay;
        long period;
        
        switch (timeInterval) {
            case HOUR:
                delay = getNextHourDelay();
                period = TimeUnit.HOURS.toMillis(1);
                break;
            case DAY:
                delay = getNextDayDelay();
                period = TimeUnit.DAYS.toMillis(1);
                break;
            case WEEK:
                delay = getNextWeekDelay();
                period = TimeUnit.DAYS.toMillis(7);
                break;
            default:
                return;
        }
        
        scheduler.scheduleAtFixedRate(() -> {
            if (enabled) {
                rotateByTime();
            }
        }, delay, period, TimeUnit.MILLISECONDS);
        
        logger.info(String.format("定时轮转已设置: %s, 首次延迟: %d毫秒, 周期: %d毫秒", 
                timeInterval, delay, period));
    }
    
    /**
     * 获取到下一个小时的延迟
     */
    private long getNextHourDelay() {
        Calendar now = Calendar.getInstance();
        Calendar nextHour = Calendar.getInstance();
        nextHour.set(Calendar.MINUTE, 0);
        nextHour.set(Calendar.SECOND, 0);
        nextHour.set(Calendar.MILLISECOND, 0);
        nextHour.add(Calendar.HOUR_OF_DAY, 1);
        
        return nextHour.getTimeInMillis() - now.getTimeInMillis();
    }
    
    /**
     * 获取到下一个天的延迟
     */
    private long getNextDayDelay() {
        Calendar now = Calendar.getInstance();
        Calendar nextDay = Calendar.getInstance();
        nextDay.set(Calendar.HOUR_OF_DAY, 0);
        nextDay.set(Calendar.MINUTE, 0);
        nextDay.set(Calendar.SECOND, 0);
        nextDay.set(Calendar.MILLISECOND, 0);
        nextDay.add(Calendar.DAY_OF_MONTH, 1);
        
        return nextDay.getTimeInMillis() - now.getTimeInMillis();
    }
    
    /**
     * 获取到下一个周的延迟
     */
    private long getNextWeekDelay() {
        Calendar now = Calendar.getInstance();
        Calendar nextWeek = Calendar.getInstance();
        nextWeek.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        nextWeek.set(Calendar.HOUR_OF_DAY, 0);
        nextWeek.set(Calendar.MINUTE, 0);
        nextWeek.set(Calendar.SECOND, 0);
        nextWeek.set(Calendar.MILLISECOND, 0);
        nextWeek.add(Calendar.WEEK_OF_YEAR, 1);
        
        return nextWeek.getTimeInMillis() - now.getTimeInMillis();
    }
    
    /**
     * 清理旧文件
     */
    private void cleanupOldFiles() {
        if (maxFiles <= 0) {
            return;
        }
        
        try {
            Path rotationPath = Paths.get(rotationDirectory);
            if (!Files.exists(rotationPath)) {
                return;
            }
            
            // 获取所有轮转文件
            List<File> rotationFiles = new ArrayList<>();
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(rotationPath)) {
                for (Path path : stream) {
                    File file = path.toFile();
                    if (file.isFile() && file.getName().startsWith(new File(baseLogFile).getName())) {
                        rotationFiles.add(file);
                    }
                }
            }
            
            // 按修改时间排序
            rotationFiles.sort((a, b) -> Long.compare(b.lastModified(), a.lastModified()));
            
            // 删除超过限制的文件
            if (rotationFiles.size() > maxFiles) {
                List<File> filesToDelete = rotationFiles.subList(maxFiles, rotationFiles.size());
                for (File file : filesToDelete) {
                    if (file.delete()) {
                        logger.info("删除旧日志文件: " + file.getName());
                    } else {
                        logger.warning("无法删除旧日志文件: " + file.getName());
                    }
                }
            }
            
        } catch (IOException e) {
            logger.severe("清理旧文件时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 关闭管理器
     */
    public void close() {
        try {
            if (currentWriter != null) {
                currentWriter.close();
            }
            if (scheduler != null) {
                scheduler.shutdown();
            }
            logger.info("日志轮转管理器已关闭");
        } catch (Exception e) {
            logger.severe("关闭日志轮转管理器时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 获取当前日志文件大小
     */
    public long getCurrentFileSize() {
        return currentFileSize;
    }
    
    /**
     * 是否启用轮转
     */
    public boolean isEnabled() {
        return enabled;
    }
}